package org.example.journal_items.common;

import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;

import java.util.stream.Collectors;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

  @ExceptionHandler(BusinessException.class)
  public Result<Void> handleBusinessException(BusinessException e) {
    log.error("业务异常：{}", e.getMessage());
    return Result.error(e.getMessage());
  }

  @ExceptionHandler(AccessDeniedException.class)
  public ResponseEntity<Result<?>> handleAccessDeniedException(AccessDeniedException e) {
    log.error("Access denied: ", e);
    return ResponseEntity.status(HttpStatus.FORBIDDEN)
        .body(Result.error(ResultCode.FORBIDDEN.getCode(), "没有权限访问该资源"));
  }

  @ExceptionHandler(BadCredentialsException.class)
  public ResponseEntity<Result<?>> handleBadCredentialsException(BadCredentialsException e) {
    log.error("Authentication failed: ", e);
    return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
        .body(Result.error(ResultCode.UNAUTHORIZED.getCode(), "用户名或密码错误"));
  }

  @ExceptionHandler(AuthenticationException.class)
  public ResponseEntity<Result<?>> handleAuthenticationException(AuthenticationException e) {
    log.error("Authentication error: ", e);
    return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
        .body(Result.error(ResultCode.UNAUTHORIZED.getCode(), "认证失败"));
  }

  @ExceptionHandler(MethodArgumentNotValidException.class)
  public ResponseEntity<Result<?>> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
    String message = e.getBindingResult().getFieldErrors().stream()
        .map(error -> error.getField() + ": " + error.getDefaultMessage())
        .collect(Collectors.joining(", "));
    log.error("Validation error: {}", message);
    return ResponseEntity.status(HttpStatus.BAD_REQUEST)
        .body(Result.error(ResultCode.VALIDATE_FAILED.getCode(), message));
  }

  @ExceptionHandler(ConstraintViolationException.class)
  public ResponseEntity<Result<?>> handleConstraintViolationException(ConstraintViolationException e) {
    String message = e.getConstraintViolations().stream()
        .map(violation -> violation.getPropertyPath() + ": " + violation.getMessage())
        .collect(Collectors.joining(", "));
    log.error("Validation error: {}", message);
    return ResponseEntity.status(HttpStatus.BAD_REQUEST)
        .body(Result.error(ResultCode.VALIDATE_FAILED.getCode(), message));
  }

  @ExceptionHandler(BindException.class)
  public ResponseEntity<Result<?>> handleBindException(BindException e) {
    String message = e.getBindingResult().getFieldErrors().stream()
        .map(error -> error.getField() + ": " + error.getDefaultMessage())
        .collect(Collectors.joining(", "));
    log.error("Binding error: {}", message);
    return ResponseEntity.status(HttpStatus.BAD_REQUEST)
        .body(Result.error(ResultCode.VALIDATE_FAILED.getCode(), message));
  }

  @ExceptionHandler(MethodArgumentTypeMismatchException.class)
  public ResponseEntity<Result<?>> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
    log.error("Argument type mismatch: ", e);
    return ResponseEntity.status(HttpStatus.BAD_REQUEST)
        .body(Result.error(ResultCode.VALIDATE_FAILED.getCode(),
            "参数类型不匹配: " + e.getName() + " 应该是 " + e.getRequiredType().getSimpleName()));
  }

  @ExceptionHandler(MissingServletRequestParameterException.class)
  public ResponseEntity<Result<?>> handleMissingServletRequestParameterException(
      MissingServletRequestParameterException e) {
    log.error("Missing parameter: ", e);
    return ResponseEntity.status(HttpStatus.BAD_REQUEST)
        .body(Result.error(ResultCode.VALIDATE_FAILED.getCode(),
            "缺少必要参数: " + e.getParameterName()));
  }

  @ExceptionHandler(MissingServletRequestPartException.class)
  public ResponseEntity<Result<?>> handleMissingServletRequestPartException(MissingServletRequestPartException e) {
    log.error("Missing request part: ", e);
    return ResponseEntity.status(HttpStatus.BAD_REQUEST)
        .body(Result.error(ResultCode.VALIDATE_FAILED.getCode(),
            "缺少必要文件: " + e.getRequestPartName()));
  }

  @ExceptionHandler(MaxUploadSizeExceededException.class)
  public ResponseEntity<Result<?>> handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) {
    log.error("File too large: ", e);
    return ResponseEntity.status(HttpStatus.BAD_REQUEST)
        .body(Result.error(ResultCode.VALIDATE_FAILED.getCode(), "文件大小超过限制"));
  }

  @ExceptionHandler(Exception.class)
  public Result<Void> handleException(Exception e) {
    log.error("系统异常：{}", e.getMessage());
    return Result.error("系统异常，请联系管理员");
  }

  @ExceptionHandler(RuntimeException.class)
  public Result<Void> handleRuntimeException(RuntimeException e) {
    log.error("运行时异常：{}", e.getMessage());
    // 如果是统计相关的异常，返回更友好的错误信息
    if (e.getMessage() != null && e.getMessage().contains("统计")) {
      return Result.error("获取统计数据失败，请稍后重试");
    }
    return Result.error("系统异常，请联系管理员");
  }
}